package com.yunyao.common.utils;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author xingjishuai
 * @date 2024-08-21
 */
public class HttpUtils {
    // 连接超时时间5秒
    private static final int CONNECT_TIMEOUT = 5 * 1000;
    // 数据读取超时时间10秒
    private static final int SOCKET_TIMEOUT = 10 * 1000;
    // 连接不受阻塞超时时间5秒
    private static final int CONNECTION_REQUEST_TIMEOUT = 5 * 1000;

    private static final CloseableHttpClient HTTP_CLIENT;

    static {
        // 设置请求配置
        RequestConfig config =
                RequestConfig.custom()
                        .setConnectTimeout(CONNECT_TIMEOUT)
                        .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
                        .setSocketTimeout(SOCKET_TIMEOUT)
                        .build();
        HTTP_CLIENT = HttpClients.custom().setDefaultRequestConfig(config).build();
    }

    /**
     * 发送GET请求
     *
     * @param url     请求的URL
     * @param headers 请求头信息，如果不需要传入null
     * @return 服务器的响应内容
     * @throws RuntimeException 如果发送GET请求过程中出现IO异常
     */
    public static String sendGet(String url, Map<String, String> headers) {
        try {
            // 创建HttpGet对象，指定请求的URL
            HttpGet httpGet = new HttpGet(url);
            // 为HttpGet请求添加请求头信息
            addHeaders(httpGet, headers);
            try (CloseableHttpResponse response = HTTP_CLIENT.execute(httpGet)) {
                // 读取并转换响应实体的内容
                return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            // 如果发送GET请求过程中出现IO异常，抛出RuntimeException
            throw new RuntimeException("Error while sending GET request", e);
        }
    }


    /**
     * 发送POST请求
     *
     * @param url     请求的URL
     * @param headers 请求头部信息，Map结构，键为头部字段名，值为头部字段值
     * @param body    请求体内容，字符串形式
     * @return 服务器响应内容，字符串形式
     * <p>
     * 此方法封装了发送HTTP POST请求的逻辑，通过提供的请求URL、头部信息和请求体内容，
     * 构建HttpPost对象并执行请求，返回服务器的响应内容。
     */
    public static String sendPost(String url, Map<String, String> headers, String body) {
        try {
            // 创建HttpPost对象，指定请求URL
            HttpPost httpPost = new HttpPost(url);

            // 添加请求头部信息到HttpPost对象中
            addHeaders(httpPost, headers);

            // 设置请求体内容，指定字符集为UTF-8
            httpPost.setEntity(new StringEntity(body, StandardCharsets.UTF_8));

            // 执行HttpPost请求，获取服务器响应
            try (CloseableHttpResponse response = HTTP_CLIENT.execute(httpPost)) {
                // 读取并返回服务器响应内容，指定字符集为UTF-8
                return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            // 在发生IO异常时抛出运行时异常，包含异常信息
            throw new RuntimeException("Error while sending POST request", e);
        }
    }


    /**
     * 向HTTP请求方法中添加请求头信息
     * <p>
     * 此方法会遍历传入的请求头信息映射，并将每一对键值对作为请求头添加到HTTP请求方法对象中
     * 如果传入的请求头信息为null，则不会进行任何操作
     *
     * @param method  HTTP请求方法对象，可以是GET、POST等
     * @param headers 请求头信息的映射，键为请求头名称，值为请求头值
     */
    private static void addHeaders(HttpRequestBase method, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                method.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

}
